#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;

#include "kddcup_feat.h"
#include <inttypes.h>
#include <cstdlib>
#include <cmath>

/*! \brief seed the PRNG */
inline void seed( uint32_t seed ){
    srand( seed );
}

/*! \brief return a real number uniform in [0,1) */
inline double next_double(){
    return static_cast<double>( rand() ) / (static_cast<double>( RAND_MAX )+1.0);
}

/*! \brief return a random number in n */
inline uint32_t next_uint32( uint32_t n ){
    return (uint32_t) floor( next_double() * n ) ;
}  

template<typename T>
inline void exchange( T &a, T &b ){
    T c;
    c = a;
    a = b;
    b = c;
}

template<typename T>
inline void shuffle( T *data, size_t sz ){
    if( sz == 0 ) return;
    for( uint32_t i = (uint32_t)sz - 1; i > 0; i-- ){
        exchange( data[i], data[ next_uint32( i+1 ) ] );
    } 
}
// random shuffle the data inside, require PRNG 
template<typename T>
inline void shuffle( std::vector<T> &data ){
    shuffle( &data[0], data.size() );
}

inline int update_stats( double &sum_all, 
                          vector<double> &sumeval, 
                          const vector< pair<float,int> >  &vec, 
                          const vector<int>  &ats ){
    int npos = 0;
    double sumap = 0.0;
    vector<float> sum_ar;
    vector<int>   pos_idx;
    for( size_t i = 0; i < vec.size(); i ++ ){
        if( vec[i].second != 0 ){
            npos ++;
            double pp = ((double)npos) / ( i + 1 );
            sumap += pp;
            sum_ar.push_back( sumap );
            pos_idx.push_back( i );
        }
    }

    if( npos == 0 ){        
        return 1;
    }else{
        sum_all += sumap / npos;
        for( size_t i = 0; i < ats.size(); i ++ ){
            size_t idx = lower_bound( pos_idx.begin(), pos_idx.end(), ats[i] ) - pos_idx.begin();
            if( idx != 0 ){
                sumeval[ i ] += sum_ar[ idx - 1 ] / npos;
            }      
        } 
    }
    return npos;
}

inline bool partial_cmp( const pair<float,int> &a, const pair<float,int> &b ){
    return a.first < b.first;
}

int main( int argc, char *argv[] ){
    if( argc < 5 ){
        printf("imfb test.group.rate pred rnd ats\n");
        return 0;
    }
    seed( 0 );
    int round = atoi( argv[4] );
    double sumall_pub = 0.0, sumall_prv = 0.0;
    vector<int>    ats;
    vector<double> sumpub;
    vector<double> sumprv;
    for( int i = 5; i < argc; i ++ ){
        ats.push_back( atoi( argv[i] ) );
        sumpub.push_back( 0.0 );
        sumprv.push_back( 0.0 );
    }
    
    FILE *fi = fopen_check( argv[2], "r" );
    FILE *fb = fopen_check( argv[1], "r" );
    FILE *fp = fopen_check( argv[3], "r" );
    int nline;
    unsigned long npub = 0, nprv = 0;
    while( fscanf( fb, "%d%*[^\n]\n", &nline ) == 1 ){
        vector< pair<float, int > > vpub, vprv;
        while( nline -- ){
            int rt, ps; float p;
            assert_true( fscanf( fi, "%d%d\n", &ps, &rt ) == 2, "BUGA" );
            assert_true( fscanf( fp, "%f", &p ) == 1, "BUGB" );
            if( ps == 0 ){
                vpub.push_back( make_pair( -p, rt ) );
            }else{
                vprv.push_back( make_pair( -p, rt ) );
            }
        }
        shuffle( vpub ); shuffle( vprv );
        sort( vpub.begin(), vpub.end(), partial_cmp );
        sort( vprv.begin(), vprv.end(), partial_cmp );
        if( update_stats( sumall_pub, sumpub, vpub, ats ) != 0 && vpub.size() != 0 ) npub ++;
        if( update_stats( sumall_prv, sumprv, vprv, ats ) != 0 && vprv.size() != 0 ) nprv ++;
    }
    fclose( fi );
    fclose( fb );
    fclose( fp );

    if( round != 0 ) printf( "%d\t", round );
    
    printf("MAPUB:%f", sumall_pub / npub );
    for( size_t i = 0; i < ats.size(); i ++ ){
        printf(" MAPUB@%d:%f", ats[i], sumpub[i] / npub );
    }
    printf(" | MAPRV:%f", sumall_prv / nprv );
    for( size_t i = 0; i < ats.size(); i ++ ){
        printf(" MAPRV@%d:%f", ats[i], sumprv[i] / nprv );
    }
    printf("\n");
    return 0;
}
